home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / snip0493.zip / XFILE.C < prev    next >
C/C++ Source or Header  |  1993-04-05  |  5KB  |  201 lines

  1. /*  xfile.c -- implementation for fast line buffered files
  2. **
  3. **  Currently (Sat  06-15-1991) XFILEs are for reading CR-LF terminated lines
  4. **  from MS-DOS text files.  Period.  It's not that the method can't be used
  5. **  as well for output buffering, or (in some form) for binary files, it's
  6. **  that such are handled fast enough to suit me already, whereas text mode
  7. **  input performance leaves me wishing for more speed.  This attempts to
  8. **  solve that problem.
  9. **
  10. **  Sun  06-16-1991 -- CR-LF accepted, but so is bare LF now; the extracted
  11. **  line does NOT have a NEWLINE at the end anymore (which will likely be
  12. **  a mixed blessing...)
  13. **
  14. **  The code should be fairly portable: if/when I get around to polishing it
  15. **  (and that won't be until I've used it some and am sure it's stable) I'll
  16. **  be aiming for near-ANSI portability; for now I'm not pushing so very hard
  17. **  for that.
  18. **
  19. **  The semantics are a bit odd: the lines are returned in a buffer that the
  20. **  XFILE owns, and may be altered by a call to xgetline or xclose.  For
  21. **  applications that resent this, XFILEs probably aren't a big win anyway,
  22. **  but there might be some cases where using XFILE and copying (some) lines
  23. **  is still a good idea.  The performance with long lines is good: it can
  24. **  handle lines the size of the buffer, though it may truncate up to one
  25. **  QUANTUM less one bytes "early": this depends on the location of the start
  26. **  of the line in the buffer when we begin scanning.  In practice, XBUFSIZE
  27. **  is probably larger than you'd set for a line buffer size anyway...
  28. **
  29. **  INTERNALS:
  30. **
  31. **  Reading the first buffer's worth at open time makes the EOF case easier to
  32. **  detect.
  33. **
  34. **  TO DO:
  35. **
  36. **  clean up xgetline!
  37. */
  38.  
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include "xfile.h"
  42.  
  43. #if !defined(__ZTC__) && !defined(__TURBOC__)
  44.  static int DOS_OPEN(const char *name, int mode, ...)
  45.  {
  46.        int hdl;
  47.  
  48.        if (0 == _dos_open(name, mode, &hdl))
  49.              return hdl;
  50.        else  return -1;
  51.  }
  52.  
  53.  static int READ(int fd, void *buf, size_t len)
  54.  {
  55.        unsigned count;
  56.  
  57.        if (0 == _dos_read(fd, buf, len, &count))
  58.              return count;
  59.        else  return -1;
  60.  }
  61. #endif
  62.  
  63. #ifndef XBUFN               /* set default # of quanta in buffer, allow -D */
  64.  #define XBUFN 8
  65. #endif
  66.  
  67. #define QUANTUM 512
  68. #define XBUFSIZE (XBUFN * QUANTUM)
  69.  
  70.  
  71. /*  xopen -- allocate and open an XFILE
  72. **
  73. **  NB: currently I'm designing these for READ-ONLY TEXT FILES only: the xopen
  74. **      interface may have to be changed...
  75. **
  76. **  returns pointer to XFILE of opened file or null pointer on error
  77. **
  78. **  ? should it leave a better error description somewhere ?
  79. */
  80.  
  81. XFILE *xopen(char const *name)
  82. {
  83.       XFILE *f = malloc(sizeof(XFILE) + XBUFSIZE + 1);
  84.       int n;
  85.  
  86.       if (f == 0)
  87.             goto error0;
  88.       f->buf = (char *)f + sizeof(XFILE);
  89.  
  90.       if ((f->fd = DOS_OPEN(name, O_RDONLY)) < 0)
  91.             goto error1;
  92.  
  93.       if ((n = READ(f->fd, f->buf, XBUFSIZE)) < 0)
  94.             goto error2;
  95.  
  96.       f->buf[n] = 0;
  97.       f->nextChar = f->buf;
  98.       return f;
  99.  
  100. error2:
  101.       CLOSE(f->fd);
  102. error1:
  103.       free(f);
  104. error0:
  105.       return 0;
  106. }
  107.  
  108.  
  109. /*
  110. **  xclose -- close and deallocate an XFILE
  111. */
  112.  
  113. void xclose(XFILE *f)
  114. {
  115.       CLOSE(f->fd);
  116.       free(f);
  117. }
  118.  
  119.  
  120. /*
  121. **  xgetline -- get the next text line into memory
  122. **
  123. **  returns a pointer to the line (a NUL-terminated string) or a null pointer
  124. */
  125.  
  126. char *xgetline(XFILE *f)
  127. {
  128.       char *s = f->nextChar, *p;
  129.       int n;
  130.  
  131.       for (p = s; *p != 0; ++p)
  132.       {
  133.             if (*p == '\n')
  134.             {
  135.                   if (s < p && p[-1] == '\r')
  136.                         p[-1] = 0;
  137.                   else  *p = 0;
  138.                   f->nextChar = p + 1;
  139.                   return s;
  140.             }
  141.       }
  142.  
  143.       /*
  144.       **  end of line not found in buffer -- p points to the sentinel NUL
  145.       */
  146.  
  147.       if (p == f->buf)                    /* iff empty, EOF */
  148.             return 0;
  149.  
  150.       /*
  151.       **  move prefix of line to bottom of buffer
  152.       */
  153.  
  154.       if (s != f->buf)
  155.       {
  156.             for (p = f->buf; (*p = *s) != 0; ++p, ++s)
  157.                   ;
  158.             s = f->buf;
  159.       }
  160.  
  161.       n = XBUFSIZE - (p - f->buf);
  162.  
  163.       if (n < QUANTUM)                    /* insufficent room, break line */
  164.       {
  165.             f->nextChar = p;
  166.             return s;
  167.       }
  168.  
  169.       n = (n / QUANTUM) * QUANTUM;        /* quantize: count to read */
  170.       n = READ(f->fd, p, n);
  171.  
  172.       /*
  173.       **  read error is sort of ignored here... same return as EOF.
  174.       **  we'll see if this proves to be sufficent...
  175.       */
  176.  
  177.       if (n < 0)
  178.       {
  179.             f->nextChar = f->buf;
  180.             f->buf[0] = 0;
  181.             return 0;
  182.       }
  183.  
  184.       p[n] = 0;
  185.  
  186.       for ( ; *p != 0; ++p)
  187.       {
  188.             if (*p == '\n')
  189.             {
  190.                   if (s < p && p[-1] == '\r')
  191.                         p[-1] = 0;
  192.                   else  *p = 0;
  193.                   ++p;
  194.                   break;
  195.             }
  196.       }
  197.  
  198.       f->nextChar = p;
  199.       return p == s ? 0 : s;
  200. }
  201.